/* Copyright (C) 2014-2016 Dan Chapman <dpniel@ubuntu.com>

   This file is part of Dekko email client for Ubuntu Devices/

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License or (at your option) version 3

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "NotificationService.h"
#include <QGuiApplication>
#include <QDebug>
#include "NotificationWorker.h"
#include "configure.cmake.h"

#define SERVICE_START_INTERVAL 10000 // 10 seconds

namespace Dekko
{
namespace Notifications
{
NotificationService::NotificationService(QObject *parent) :
    QObject(parent), m_manager(0), m_emblemCounter(0), m_timer(0), m_postalService(0), m_running(false)
{

#ifdef UNCONFINED
    m_emblemCounter = new Launcher::EmblemCounter(this);
    connect(qApp, &QGuiApplication::applicationStateChanged, this, &NotificationService::handleAppStateChanged);
    m_timer = new QTimer(this);
    m_timer->setInterval(SERVICE_START_INTERVAL);
    connect(m_timer, SIGNAL(timeout()), this, SLOT(startNotificationService()));
    m_postalService = new PostalServiceWorker(this);
#endif
}

//NotificationService::~NotificationService()
//{
//    if (m_workerThread.isRunning() && m_useBackgroundThread) {
//        m_workerThread.quit();
//        m_workerThread.wait();
//    }
//}

void NotificationService::setManager(QObject *manager)
{
    m_manager = qobject_cast<Accounts::AccountsManager*>(manager);
    qDebug() << "Manager set";
#ifdef UNCONFINED
    connect(m_manager, &Accounts::AccountsManager::unreadCountChanged, m_emblemCounter, &Launcher::EmblemCounter::setCount);
#endif
}

void NotificationService::updateUnreadCount(const int &count)
{
    m_emblemCounter->setCount(count);
}

void NotificationService::sendNotification(QSharedPointer<PostalMessage> notification)
{
    m_postalService->sendNotification(notification);
}

void NotificationService::handleAppStateChanged(const Qt::ApplicationState &state)
{
    if (m_manager.isNull()) {
        qDebug() << "Manager is null";
        return;
    }
    qDebug() << "App state changed";

    switch (state) {
    case Qt::ApplicationActive:
        qDebug() << "APPLICATION ACTIVE";
        if (m_timer->isActive()) {
            m_timer->stop();
        }
        m_postalService->removeAllSources();
        if (m_running) {
            return;
        }
        qDebug() << "Stopping notification service";
        stopNotificationService();
        break;
    case Qt::ApplicationSuspended:
    case Qt::ApplicationHidden:
    case Qt::ApplicationInactive:
        qDebug() << "Starting timer";
        if (m_running) {
            // update the start time notifications should be compare with.
            // Were not concerned with messages that arrived before going inactive.
            emit updateStartTime(QDateTime::currentDateTime());
        } else {
            m_timer->start();
        }
        break;
    }
}

void NotificationService::startNotificationService()
{
    m_running = true;
    qDebug() << "Starting notification service ";
    m_timer->stop();
    // Start by setting the imapModels consumed by the UI offline
//    setImapModelConnectionState(OFFLINE);
    // Now connect the notificationModel signals & connect the manager
    // to our notification slots
    connectNotificationModels();
    // create new notification worker
}

void NotificationService::stopNotificationService()
{
    if (!m_running)
        return;
    m_running = false;
    setImapModelConnectionState(ONLINE);

    // Delete all notification workers
    Q_FOREACH(NotificationWorker *worker, m_workers) {
        disconnect(worker, &NotificationWorker::newMessage, m_postalService, &PostalServiceWorker::sendNotification);
        qDebug() << "Deleting worker";
        delete worker;
        worker = 0;
    }
    m_workers.clear();
    qDebug() << "Number of notification workers: " << m_workers.count();

    disconnectNotificationModels();
}

void NotificationService::handleImapError(const QString &error)
{
    Accounts::Account *account = qobject_cast<Accounts::Account *>(sender());
    Q_ASSERT(account);
    sendErrorMessage(account, error, QString());
}

void NotificationService::handleAlert(const QString &alert)
{
    qDebug() << "NS >>> Received IMAP ALERT: " << alert;
}

void NotificationService::handleAuthAttemptFailed(const QString &authError)
{
    qDebug() << "NS >>> Authentication Failed: " << authError;
}

void NotificationService::setImapModelConnectionState(const ImapModelState state)
{
    auto it = m_manager->m_accountsList.begin();
    while (it != m_manager->m_accountsList.end()) {
        Accounts::Account *account = *it;
        if (m_manager->accountHasImapCapability(account)) {
            bool online = false;
            switch (state) {
            case OFFLINE:
                online = false;
            case ONLINE:
                online = true;
            }
            account->setNetworkOnline(online);
            qDebug() << "ImapModel offline: " << account->isOnline();
        }
        ++it;
    }
}

void NotificationService::connectNotificationModels()
{
    auto it = m_manager->m_accountsList.begin();
    while (it != m_manager->m_accountsList.end()) {
        Accounts::Account *account = *it;
        if (m_manager->accountHasImapCapability(account)) {
            connect(account->notificationModel(),
                    SIGNAL(imapError(QString)),
                    this,
                    SLOT(handleImapError(QString)));
            connect(account->notificationModel(),
                    SIGNAL(alertReceived(QString)),
                    this,
                    SLOT(handleAlert(QString)));
            connect(account->notificationModel(),
                    SIGNAL(authRequested()),
                    m_manager,
                    SLOT(showAuthRequested()));
            connect(account->notificationModel(),
                    SIGNAL(authAttemptFailed(QString)),
                    m_manager,
                    SLOT(showAuthAttemptFailed(QString)));
            connect(account->notificationModel(),
                    SIGNAL(messageCountPossiblyChanged(QModelIndex)),
                    m_manager,
                    SLOT(handleUnreadCountPossiblyChanged(QModelIndex)));
//            connect(account,
//                    SIGNAL(checkSslPolicy()),
//                    this,
//                    SLOT(showCheckSslPolicy()));
            NotificationWorker *worker = new NotificationWorker(this, account);
            connect(worker, &NotificationWorker::newMessage, m_postalService, &PostalServiceWorker::sendNotification);
            connect(worker, &NotificationWorker::messageNowMarkedRead, m_postalService, &PostalServiceWorker::clearPersistentMessage);
            connect(this, &NotificationService::updateStartTime, worker, &NotificationWorker::updateStartTime);
            m_workers.append(worker);
        }
        ++it;
    }
    // connect manager to our notification slots.
    qDebug() << "Number of notification workers: " << m_workers.count();

}

void NotificationService::disconnectNotificationModels()
{
    auto it = m_manager->m_accountsList.begin();
    while (it != m_manager->m_accountsList.end()) {
        Accounts::Account *account = *it;
        if (m_manager->accountHasImapCapability(account)) {
            disconnect(account->notificationModel(),
                    SIGNAL(imapError(QString)),
                    this,
                    SLOT(handleImapError(QString)));
            disconnect(account->notificationModel(),
                    SIGNAL(alertReceived(QString)),
                    this,
                    SLOT(handleAlert(QString)));
            disconnect(account->notificationModel(),
                    SIGNAL(authRequested()),
                    m_manager,
                    SLOT(showAuthRequested()));
            disconnect(account->notificationModel(),
                    SIGNAL(authAttemptFailed(QString)),
                    m_manager,
                    SLOT(showAuthAttemptFailed(QString)));
//            connect(account,
//                    SIGNAL(checkSslPolicy()),
//                    this,
//                    SLOT(showCheckSslPolicy()));
        }
        ++it;
    }
}

void NotificationService::sendErrorMessage(Accounts::Account *account, const QString &message, const QString &icon)
{
    Dekko::Settings::AccountProfile *profile = static_cast<Dekko::Settings::AccountProfile*>(account->profile());
    ErrorMessage *msg = new ErrorMessage();
    msg->accountId = account->accountId();
    msg->title = profile->description();
    msg->body = message;
    msg->icon = icon;
    msg->time = QDateTime::currentDateTime();
    m_postalService->sendErrorNotification(msg);
}


//void NotificationService::start()
//{
//    qDebug() << "STARTING SERVICE";
//    connect(this, &NotificationService::openConnections, &m_worker, &NotificationWorker::openConnections);
//    connect(this, &NotificationService::closeConnections, &m_worker, &NotificationWorker::closeConnections);
//    connect(this, &NotificationService::setNetworkPolicy, &m_worker, &NotificationWorker::setNetworkPolicy);
//    connect(&m_worker, SIGNAL(logMessage(QString)), this, SLOT(logMessage(QString)));
//    connect(&m_worker, SIGNAL(newMessage(PostalMessage*)), m_postalService, SLOT(sendPost(PostalMessage*)));
//    connect(&m_worker, SIGNAL(messageNowMarkedRead(PostalMessage*)), m_postalService, SLOT(clearPersistentMessage(PostalMessage*)));
//    connect(&m_worker, SIGNAL(unreadCountChanged(int)), m_postalService, SLOT(setCount(int)));
//    if (m_useBackgroundThread) {
//        qDebug() << "STARTING BACKGROUND THREAD";
//        m_worker.moveToThread(&m_workerThread);
//        connect(&m_workerThread, SIGNAL(finished()), &m_worker, SLOT(deleteLater()));
//        m_workerThread.start();
//        qDebug() << "SERVICE RUNNING: " << m_workerThread.isRunning();
//    }
//}

//void NotificationService::stop()
//{
//    if (m_workerThread.isRunning() && m_useBackgroundThread) {
//        m_workerThread.quit();
//        m_workerThread.wait();
//    }
//    disconnect(this, &NotificationService::openConnections, &m_worker, &NotificationWorker::openConnections);
//    disconnect(this, &NotificationService::closeConnections, &m_worker, &NotificationWorker::closeConnections);
//    disconnect(this, &NotificationService::setNetworkPolicy, &m_worker, &NotificationWorker::setNetworkPolicy);
//}

//bool NotificationService::isRunning() const
//{
//    return m_workerThread.isRunning();
//}

//void NotificationService::sendPostalMessage(PostalMessage *message)
//{
//    PostalMessage *msg = message;
//    qDebug() << ">>>> NotificationsService >>> MESSAGE RECEIVED: FROM: " << msg->from << "SUBJECT:" << msg->subject;
//    m_postalService->sendPost(msg);
//}

//void NotificationService::logMessage(QString &message)
//{
//    qDebug() << message;
//}
}
}
